home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / TURB_VIS / OGRID100 / GLSORT.PAS < prev    next >
Pascal/Delphi Source File  |  1994-12-28  |  13KB  |  380 lines

  1. {********************************************************************
  2.  
  3.   OOGrid Library(TM) v1.0 for Borland/Turbo Pascal (Real Mode/TV)
  4.   Copyright (C) 1994 by Arturo J. Monge
  5.   Portions Copyright (C) 1989,1990 Borland International, Inc.
  6.  
  7.   OOGrid Library(TM) Sort Unit:
  8.     This unit implements an object that can sort a block
  9.     of cells in a TCellHashTable object using three different
  10.     sort keys in either ascending or desceding order.
  11.  
  12.   Copyright (C) 1994 by Arturo J. Monge
  13.  
  14.   Last Modification : December 29th, 1994
  15.  
  16. *********************************************************************}
  17.  
  18. {$O+,F+,N+,E+,X+}
  19.  
  20. unit GLSort;
  21.  
  22. {****************************************************************************}
  23.                                  interface
  24. {****************************************************************************}
  25.  
  26. uses Objects, Views, GLCell, GLSupprt;
  27.  
  28. type
  29.   SortTypes = (Ascending, Descending);
  30.  
  31.   KeyPosition = (BeforePivot, SameAsPivot, AfterPivot);
  32.   { Values returned after comparing a key with the pivot according
  33.     to the sort order requested }
  34.  
  35.   KeyValue = record
  36.   { Used to store the values to be compared }
  37.      Error : Boolean;
  38.      case CellType : CellTypes of
  39.        ClText,
  40.        ClRepeat : (StrValue: String);
  41.        ClValue,
  42.        ClFormula : (Value: Extended);
  43.   end; {...KeyValue }
  44.  
  45.  
  46.   PSortObject = ^TSortObject;
  47.   TSortObject = object(TObject)
  48.   { Will sort a block of cells in ascending or descending order,
  49.     given up to three sort keys, using the QuickSort algorithm }
  50.        KeySortOrder : array[1..3] of SortTypes;
  51.        KeyCols : array[1..3] of Word;
  52.        LastKey : Byte;
  53.        SourceHash: PCellHashTable;
  54.        CurrentKey, PivotFirstKey, PivotSecondKey, PivotThirdKey: KeyValue;
  55.        SortBlock : TBlock;
  56.     constructor Init(SourceCellHash: PCellHashTable);
  57.     function CurrentKeyPosition(var ComparedRec, PivotRec: KeyValue;
  58.       SortOrder: SortTypes): KeyPosition;
  59.     function CurrentRowPosition(CurrRow: Word): KeyPosition;
  60.     procedure FillKeyRec(SearchCell: CellPos; var KeyRecord: KeyValue);
  61.     procedure QuickSort(FirstRow, LastRow: Word);
  62.     function SetKeyArray(FirstKey, SecondKey, ThirdKey: Word;
  63.       FirstOrder, SecondOrder, ThirdOrder: SortTypes) : Boolean;
  64.     procedure SetPivot(Row: Word);
  65.     procedure Sort(ASortBlock: TBlock;
  66.       FirstKey: Word; AFirstKeySortOrder: SortTypes; SecondKey: Word;
  67.       ASecondKeySortOrder: SortTypes; ThirdKey: Word;
  68.       AThirdKeySortOrder: SortTypes);
  69.     procedure SplitSortBlock(FirstRow, LastRow : Word; var LowFirstRow,
  70.       LowLastRow, HighFirstRow, HighLastRow : Word);
  71.     procedure SwapRows(Row1, Row2: Word);
  72.   end; {...TSortObject }
  73.  
  74. var
  75.   StandardSortObject : PSortObject;
  76.  
  77. {****************************************************************************}
  78.                                implementation
  79. {****************************************************************************}
  80.  
  81. uses TCUtil, MsgBox;
  82.  
  83. {****************************************************************************}
  84. {**                              TSortObject                               **}
  85. {****************************************************************************}
  86.  
  87. constructor TSortObject.Init(SourceCellHash: PCellHashTable);
  88. begin
  89.   TObject.Init;
  90.   SourceHash := SourceCellHash;
  91. end; {...TSortObject.Init }
  92.  
  93. function TSortObject.CurrentKeyPosition(var ComparedRec, PivotRec: KeyValue;
  94.   SortOrder: SortTypes): KeyPosition;
  95. { Determines whether the compared record is smaller, equal or bigger than
  96.   reference record }
  97. var
  98.   Smaller, Bigger : KeyPosition;
  99. const
  100.   Value : set of CellTypes = [ClValue, ClFormula];
  101.   Text : set of CellTypes = [ClText, ClRepeat];
  102. begin
  103.   case SortOrder of
  104.     Ascending :
  105.       begin
  106.         Smaller := BeforePivot;
  107.         Bigger := AfterPivot;
  108.       end; {...case SortOrder of Ascending }
  109.     else
  110.       begin
  111.         Smaller := AfterPivot;
  112.         Bigger := BeforePivot;
  113.       end; {...case else }
  114.   end; {..case SortOrder }
  115.   if ComparedRec.Error and PivotRec.Error then
  116.     CurrentKeyPosition := SameAsPivot
  117.   else if ComparedRec.Error and (not PivotRec.Error) then
  118.     CurrentKeyPosition := Bigger
  119.   else if (not ComparedRec.Error) and PivotRec.Error then
  120.     CurrentKeyPosition := Smaller
  121.   else
  122.     begin
  123.       if ComparedRec.CellType <> PivotRec.CellType then
  124.         begin
  125.           if ((ComparedRec.CellType in Value) and (PivotRec.CellType
  126.              in Text)) or (not (ComparedRec.CellType = ClEmpty) and
  127.              (PivotRec.CellType = ClEmpty)) then
  128.             CurrentKeyPosition := Smaller
  129.           else
  130.             CurrentKeyPosition := Bigger;
  131.         end {...if ComparedRec.CellType <> PivotRec.CellType }
  132.       else
  133.         begin
  134.           case ComparedRec.CellType of
  135.             ClEmpty : CurrentKeyPosition := SameAsPivot;
  136.             ClText, ClRepeat :
  137.               begin
  138.                 if ComparedRec.StrValue < PivotRec.StrValue then
  139.                   CurrentKeyPosition := Smaller
  140.                 else if ComparedRec.StrValue = PivotRec.StrValue then
  141.                   CurrentKeyPosition := SameAsPivot
  142.                 else
  143.                   CurrentKeyPosition := Bigger;
  144.               end; {...case CellType of ClText, ClRepeat }
  145.             else
  146.               begin
  147.                 if ComparedRec.Value < PivotRec.Value then
  148.                   CurrentKeyPosition := Smaller
  149.                 else if ComparedRec.Value = PivotRec.Value then
  150.                   CurrentKeyPosition := SameAsPivot
  151.                 else
  152.                   CurrentKeyPosition := Bigger;
  153.               end; {...case else }
  154.           end; {...case ComparedRec.CellType of }
  155.         end; {...if/else }
  156.     end; {...if/else }
  157. end; {...TSortObject.CurrentKeyPosition }
  158.  
  159.  
  160. function TSortObject.CurrentRowPosition(CurrRow: Word): KeyPosition;
  161. { Compares a row in the spreadsheet with the pivot row }
  162. var
  163.   CurrKey : Byte;
  164.   CurrentPos: CellPos;
  165.   Position : KeyPosition;
  166. begin
  167.   CurrentPos.Row := CurrRow;
  168.   CurrentPos.Col := KeyCols[1];
  169.   FillKeyRec(CurrentPos, CurrentKey);
  170.   Position := CurrentKeyPosition(CurrentKey, PivotFirstKey, KeySortOrder[1]);
  171.   if (Position <> SameAsPivot) or (LastKey = 1) then
  172.     CurrentRowPosition := Position
  173.   else
  174.     begin
  175.       CurrentPos.Col := KeyCols[2];
  176.       FillKeyRec(CurrentPos, CurrentKey);
  177.       Position := CurrentKeyPosition(CurrentKey, PivotSecondKey,
  178.         KeySortOrder[2]);
  179.       if (Position <> SameAsPivot) or (LastKey = 2) then
  180.         CurrentRowPosition := Position
  181.       else
  182.         begin
  183.           CurrentPos.Col := KeyCols[3];
  184.           FillKeyRec(CurrentPos, CurrentKey);
  185.           CurrentRowPosition := CurrentKeyPosition(CurrentKey, PivotThirdKey,
  186.             KeySortOrder[3]);
  187.         end; {...if/else }
  188.     end; {...if/else }
  189. end; {...TSortObject.CurrentRowPosition }
  190.  
  191.  
  192. procedure TSortObject.FillKeyRec(SearchCell: CellPos; var KeyRecord: KeyValue);
  193. { Fills a KeyValue record with the necesary information about a cell }
  194. var
  195.   CellPtr : PCell;
  196. begin
  197.   CellPtr := SourceHash^.Search(SearchCell);
  198.   with KeyRecord do
  199.   begin
  200.     Error := CellPtr^.HasError;
  201.     CellType := CellPtr^.CellType;
  202.     case CellType of
  203.       ClText, ClRepeat : StrValue := UpperCase(CellPtr^.CopyString);
  204.       ClFormula, ClValue : Value := CellPtr^.CurrValue;
  205.     end; {...case CellType of }
  206.   end; {...with KeyRecord }
  207. end; {...TSortObject.FillKeyRec }
  208.  
  209.  
  210. procedure TSortObject.QuickSort(FirstRow, LastRow: Word);
  211. { Sorts the cells between the firstrow and lastrow of a block of cells,
  212.   using the quicksort algorithm }
  213. var
  214.   LowFirstRow, LowLastRow, HighFirstRow, HighLastRow: Word;
  215. begin
  216.   if FirstRow < LastRow then
  217.   begin
  218.     SplitSortBlock(FirstRow, LastRow, LowFirstRow, LowLastRow, HighFirstRow,
  219.       HighLastRow);
  220.     QuickSort(LowFirstRow, LowLastRow);
  221.     QuickSort(HighFirstRow, HighLastRow);
  222.   end; {...if FirstRow < LastRow }
  223. end; {...TSortObject.QuickSort }
  224.  
  225.  
  226. function TSortObject.SetKeyArray(FirstKey, SecondKey, ThirdKey: Word;
  227.   FirstOrder, SecondOrder, ThirdOrder: SortTypes) : Boolean;
  228. { Puts each key column number and sort order in the KeyCols and KeySortOrder
  229.   arrays respectively, and determines the number of valid keys }
  230. var
  231.   CurrKey : Byte;
  232. begin
  233.   CurrKey := 1;
  234.   if FirstKey <> 0 then
  235.   begin
  236.     KeyCols[CurrKey] := FirstKey;
  237.     KeySortOrder[CurrKey] := FirstOrder;
  238.     Inc(CurrKey);
  239.   end; {...if FirstKey <> 0 }
  240.   if SecondKey <> 0 then
  241.   begin
  242.     KeyCols[CurrKey] := SecondKey;
  243.     KeySortOrder[CurrKey] := SecondOrder;
  244.     Inc(CurrKey);
  245.   end; {...if SecondKey <> 0 }
  246.   if ThirdKey <> 0 then
  247.   begin
  248.     KeyCols[CurrKey] := ThirdKey;
  249.     KeySortOrder[CurrKey] := ThirdOrder;
  250.     Inc(CurrKey);
  251.   end; {...if ThirdKey <> 0 }
  252.   LastKey := Pred(CurrKey);
  253.   if LastKey = 0 then
  254.     SetKeyArray := False
  255.   else
  256.     SetKeyArray := True;
  257. end; {...TSortObject.SetKeyArray }
  258.  
  259.  
  260. procedure TSortObject.SetPivot(Row: Word);
  261. { Fills each of the pivot keyvalue records }
  262. var
  263.   SearchCell: CellPos;
  264. begin
  265.   SearchCell.Row := Row;
  266.   SearchCell.Col := KeyCols[1];
  267.   FillKeyRec(SearchCell, PivotFirstKey);
  268.   SearchCell.Col := KeyCols[2];
  269.   FillKeyRec(SearchCell, PivotSecondKey);
  270.   SearchCell.Col := KeyCols[3];
  271.   FillKeyRec(SearchCell, PivotThirdKey);
  272. end; {...TSortObject.SetPivot }
  273.  
  274.  
  275. procedure TSortObject.Sort(ASortBlock: TBlock; FirstKey: Word;
  276.   AFirstKeySortOrder: SortTypes; SecondKey: Word;
  277.   ASecondKeySortOrder: SortTypes; ThirdKey: Word;
  278.   AThirdKeySortOrder: SortTypes);
  279. { Sorts a list or block of cells in a cell hash table, using the QuickSort
  280.   algorithm }
  281. begin
  282.   if not SetKeyArray(FirstKey, SecondKey, ThirdKey, AFirstKeySortOrder,
  283.      ASecondKeySortOrder, AThirdKeySortOrder) then
  284.     Exit;
  285.   Move(ASortBlock, SortBlock, SizeOf(ASortBlock));
  286.   QuickSort(SortBlock.Start.Row, SortBlock.Stop.Row);
  287. end; {...TSortObject.Sort }
  288.  
  289.  
  290.  
  291. procedure TSortObject.SplitSortBlock(FirstRow, LastRow : Word;
  292.   var LowFirstRow, LowLastRow, HighFirstRow, HighLastRow : Word);
  293. { Splits the block into two sub-blocks: one with rows that have key
  294.   values smaller than the pivot's value and the other, with rows
  295.   that have key values bigger than the pivot's value.  The block is
  296.   not really divided;  this fuction just returns the values of the
  297.   first and last rows of each virtual sub-block }
  298. var
  299.   i_row, j_row : word;
  300. begin
  301.   SetPivot(((FirstRow + LastRow) div 2));
  302.   i_row := Pred(FirstRow);
  303.   j_row := Succ(LastRow);
  304.   repeat
  305.     repeat
  306.       Inc(i_row);
  307.     until (CurrentRowPosition(i_row) in [AfterPivot, SameAsPivot]);
  308.     repeat
  309.       Dec(j_row);
  310.     until (CurrentRowPosition(j_row) in [BeforePivot, SameAsPivot]);
  311.     if (i_row < j_row) then
  312.       SwapRows(i_row, j_row);
  313.   until (i_row >= j_row);
  314.   LowFirstRow := FirstRow;
  315.   HighLastRow := LastRow;
  316.   if (i_row = j_row) then
  317.     begin
  318.       LowLastRow := Pred(j_row);
  319.       HighFirstRow := Succ(i_row);
  320.     end {...if (i_row = j_row) }
  321.   else
  322.     begin
  323.       LowLastRow := j_row;
  324.       HighFirstRow := i_row;
  325.     end; {...if/else }
  326. end; {...TSortObject.SplitSortBlock }
  327.  
  328.  
  329. procedure TSortObject.SwapRows(Row1, Row2 : Word);
  330. { Swaps the position of two rows in the spreadsheet }
  331. var
  332.   Deleted : Boolean;
  333.   Pos : CellPos;
  334.   DestCell, SrcCell : PCell;
  335. begin
  336.   with SourceHash^ do
  337.   begin
  338.     for Pos.Col := SortBlock.Start.Col to SortBlock.Stop.Col do
  339.     begin
  340.       Pos.Row := Row1;
  341.       Delete(Pos, SrcCell);
  342.       Pos.Row := Row2;
  343.       Delete(Pos, DestCell);
  344.       if SrcCell <> NIL then
  345.       begin
  346.         SrcCell^.Loc.Row := Row2;
  347.         SourceHash^.Add(SrcCell);
  348.       end; {...if SrcCell <> NIL }
  349.       if DestCell <> NIL then
  350.       begin
  351.         DestCell^.Loc.Row := Row1;
  352.         SourceHash^.Add(DestCell);
  353.       end; {...if DestCell <> NIL }
  354.     end; {...for Pos.Col }
  355.   end; {...with SourceHash^ }
  356. end; {...TSortObject.SwapRows }
  357.  
  358. {****************************************************************************}
  359. {**                            Exit Procedure                              **}
  360. {****************************************************************************}
  361.  
  362. var
  363.   SavedExitProc : Pointer;
  364.  
  365. procedure GLSortExit; far;
  366. begin
  367.   Dispose(StandardSortObject, Done);
  368.   ExitProc := SavedExitProc;
  369. end; {...GLSortExit }
  370.  
  371. {****************************************************************************}
  372. {**                    Unit's initialization Section                       **}
  373. {****************************************************************************}
  374.  
  375. begin
  376.   SavedExitProc := ExitProc;
  377.   ExitProc := @GLSortExit;
  378.   New(StandardSortObject, Init(NIL));
  379. end. {...GLSort unit }
  380.